#pragma once
#include "http_context.hpp"
#include "http.hpp"
#include "../muduo/tcp_server.hpp"

namespace Http
{
#define DEFAULT_TIMEOUT 10
    //用于实现Http服务器的搭建
    class HttpServer
    {
    public:
        using Handler = std::function<void(const HttpRequest &,HttpResponse*)>;//请求方法+资源路径:函数指针
        using Handlers = std::vector<std::pair<std::regex,Handler>>;
        HttpServer(int port,int timeout = DEFAULT_TIMEOUT):_server(port)
        {
            _server.EnableInactiveRelease(timeout);
            _server.SetConnectedCallback(std::bind(&HttpServer::OnConnected,this,std::placeholders::_1));
            _server.SetMessageCallback(std::bind(&HttpServer::OnMessage,this,std::placeholders::_1,std::placeholders::_2));
        }

        //设置相对根目录
        void SetBaseDir(const std::string & path)
        {
            assert(Util::IsDirectory(path) == true);
            _basedir = path;
        }

        //设置Get请求的路由
        void Get(const std::string & pattern,const Handler & handler)
        {
            _get_route.push_back(std::make_pair(std::regex(pattern),handler));
        }

        //设置Post请求的路由
        void Post(const std::string & pattern,const Handler & handler)
        {
            _post_route.push_back(std::make_pair(std::regex(pattern),handler));
        }

        //设置Put请求的路由
        void Put(const std::string & pattern,const Handler & handler)
        {
            _put_route.push_back(std::make_pair(std::regex(pattern),handler));
        }

        //设置Delete请求的路由
        void Delete(const std::string & pattern,const Handler & handler)
        {
            _delete_route.push_back(std::make_pair(std::regex(pattern),handler));
        }

        //设置线程池数量
        void SetThreadCount(int count)
        {
            _server.SetThreadCount(count);
        }

        //开始监听
        void Listen()
        {
            _server.Start();
        }

    private:
        void ErrorHandler(const HttpRequest & req,HttpResponse *rsp)
        {
            //组织一个错误展示页面
            std::string body;
            body += "<html>";
            body += "<head>";
            body += "<meta http-equiv='Content-Type' content='text/html;charset=utf-8'>";
            body += "<meta name='viewport' content='width=device-width, initial-scale=1.0'>";
            body += "<title>404 - 页面未找到</title>";
            body += "<style>";
            body += "@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;600&display=swap');";
            body += "body {";
            body += "  font-family: 'Poppins', sans-serif;";
            body += "  background-color: #f4f4f9;";
            body += "  display: flex;";
            body += "  justify-content: center;";
            body += "  align-items: center;";
            body += "  height: 100vh;";
            body += "  margin: 0;";
            body += "}";
            body += ".container {";
            body += "  text-align: center;";
            body += "}";
            body += ".message-box {";
            body += "  background-color: #ffffff;";
            body += "  padding: 40px;";
            body += "  border: 2px solid #008cba;";
            body += "  border-radius: 12px;";
            body += "  box-shadow: 0 10px 20px rgba(0,0,0,0.1);";
            body += "  display: inline-block;";
            body += "  animation: fadeIn 0.5s ease;";
            body += "}";
            body += "@keyframes fadeIn {";
            body += "  from {";
            body += "    opacity: 0;";
            body += "    transform: translateY(-20px);";
            body += "  }";
            body += "  to {";
            body += "    opacity: 1;";
            body += "    transform: translateY(0);";
            body += "  }";
            body += "}";
            body += ".status {";
            body += "  font-size: 80px;";
            body += "  color: #008cba;";
            body += "  font-weight: 600;";
            body += "  margin-bottom: 20px;";
            body += "}";
            body += ".desc {";
            body += "  font-size: 24px;";
            body += "  color: #555;";
            body += "  margin-bottom: 20px;";
            body += "}";
            body += ".link {";
            body += "  display: inline-block;";
            body += "  padding: 12px 30px;";
            body += "  background-color: #008cba;";
            body += "  color: #ffffff;";
            body += "  font-size: 18px;";
            body += "  font-weight: 500;";
            body += "  border-radius: 8px;";
            body += "  text-decoration: none;";
            body += "  box-shadow: 0 4px 8px rgba(0,0,0,0.1);";
            body += "  transition: background-color 0.3s, transform 0.2s;";
            body += "}";
            body += ".link:hover {";
            body += "  background-color: #005f73;";
            body += "  transform: translateY(-2px);";
            body += "}";
            body += ".icon {";
            body += "  width: 120px;";
            body += "  height: 120px;";
            body += "  margin-bottom: 20px;";
            body += "}";
            body += "</style>";
            body += "</head>";
            body += "<body>";
            body += "<div class='container'>";
            body += "  <div class='message-box'>";
            body += "    <img class='icon' src='https://cdn-icons-png.flaticon.com/512/2748/2748558.png' alt='404 Icon'>";
            body += "    <div class='status'>" + std::to_string(rsp->_statu) + "</div>";
            body += "    <div class='desc'>" + Util::StatuDesc(rsp->_statu) + "</div>";
            body += "    <a class='link' href='/index.html'>返回首页</a>";
            body += "  </div>";
            body += "</div>";
            body += "</body>";
            body += "</html>";
            //将页面数据当做响应正文,放入rsp中
            rsp->SetContent(body, "text/html");
        }

        //将响应发送给客户端
        void WriteResponse(const Muduo::Connection::PtrConnection& conn,const HttpRequest & req,HttpResponse & rsp)
        {
            //先完善头部字段
            //将rsp中的要素,按照http协议格式进行组织
            if(req.Close() == true)
            {
                //短连接
                rsp.SetHeader("Connection","close");
            }
            else
            {
                //长连接
                rsp.SetHeader("Connection","keep-alive");
            }
            //正文长度
            if(!rsp._body.empty()&&!rsp.HasHeader("Content-Length"))
            {
                rsp.SetHeader("Content-Length",std::to_string(rsp._body.size()));
            }
            //正文类型
            if(!rsp._body.empty()&&!rsp.HasHeader("Content-Type"))
            {
                rsp.SetHeader("Content-Type","application/octet-stream");
            }
            //重定向
            if(rsp._redirect_flag)
            {
                rsp.SetHeader("Location",rsp._redirect_url);
            }
            std::stringstream rsp_str;
            //协议版本,状态码,状态码描述
            rsp_str<<req._version<<" "<<std::to_string(rsp._statu)<<" "<<Util::StatuDesc(rsp._statu)<<"\r\n";
            //头部字段
            for(auto & head:rsp._headers)
            {
                rsp_str<<head.first<<": "<<head.second<<"\r\n";
            }
            rsp_str<<"\r\n";//空行
            rsp_str<<rsp._body;
            conn->Send(rsp_str.str().c_str(),rsp_str.str().size());
        }

        //判断是否是静态资源请求
        bool IsFileHandler(const HttpRequest & req)
        {
            //必须设置相对根目录
            if(_basedir.empty())
            {
                return false;
            }
            //必须是GET或者HEAD
            if(req._method != "GET"&&req._method != "HEAD")
            {
                return false;
            }
            //资源路径必须是合法的
            if(Util::ValidPath(req._path) == false)
            {
                return false;
            }
            //资源路径必须存在
            std::string req_path = _basedir+req._path;
            //如果请求的是目录'/','/image/',在后面追加"index.html"
            if(req._path.back() == '/')
            {
                req_path +="index.html";
            }
            if(Util::IsRegular(req_path) == false)
            {
                return false;
            }
            return true;
        }

        //静态资源请求
        void FileHandler(const HttpRequest & req,HttpResponse * rsp)
        {
            std::string req_path = _basedir+req._path;
            if(req._path.back() == '/')
            {
                req_path +="index.html";
            }
            bool ret = Util::ReadFile(req_path,&rsp->_body);
            if(ret == false) return;
            std::string mime = Util::ExtMime(req_path);
            rsp->SetHeader("Content-Type",mime);
        }

        //功能性请求的分发处理
        void Dispatcher(HttpRequest & req,HttpResponse * rsp,Handlers & handlers)
        {
            //查找是否含有对应的处理方法
            for(auto & handler:handlers)
            {
                // /numbers/(\d+)
                const std::regex & re = handler.first;
                const Handler & functor = handler.second;
                bool ret = std::regex_match(req._path,req._matches,re);
                if(ret == false) continue;
                return functor(req,rsp);
            }
            rsp->_statu = 404;
        }

        //静态资源请求:功能请求
        void Route(HttpRequest & req,HttpResponse * rsp)
        {
            //对请求进行分辨,是一个静态资源请求还是一个功能性请求
            if(IsFileHandler(req))
            {
                //静态资源请求处理
                return FileHandler(req,rsp);
            }
            //功能性请求的查找
            if(req._method == "GET"||req._method == "HEAD")
            {
                return Dispatcher(req,rsp,_get_route);
            }
            else if(req._method == "POST")
            {
                return Dispatcher(req,rsp,_post_route);
            }
            else if(req._method == "PUT")
            {
                return Dispatcher(req,rsp,_put_route);
            }
            else if(req._method == "DELETE")
            {
                return Dispatcher(req,rsp,_delete_route);
            }
            //不是静态资源请求,也没有设置功能性请求处理
            rsp->_statu = 405;//Method Not Allowed
        }

        //设置上下文
        void OnConnected(const Muduo::Connection::PtrConnection & conn)
        {
            conn->SetContext(HttpContext());//设置上下文
            DLOG("new connection:%p",conn.get());
        }

        //获取上下文进行处理
        void OnMessage(const Muduo::Connection::PtrConnection & conn,Muduo::Buffer * buffer)
        {
            //获取上下文->对缓冲区数据进行解析->请求路由+业务处理->对HttpResponse进行组织->根据长短连接进行释放或者其他处理
            while(buffer->ReadAbleSize()>0)
            {
                HttpContext * context = conn->GetContext()->get<HttpContext>();
                context->RecvHttpRequest(buffer);//进行解析
                HttpRequest & req = context->Request();
                HttpResponse rsp(context->RespStatu());
                if(context->RespStatu() >=400)
                {
                    //出错了
                    ErrorHandler(req,&rsp);
                    WriteResponse(conn,req,rsp);//组织响应发送给客户端
                    context->ReSet();//这里需要重置,不然RespStatu()一直都是>=400,而且处于Recve_http_error状态
                    buffer->MoveReadOffset(buffer->ReadAbleSize());//出错了就把缓冲区数据清空
                    conn->Shutdown();//关闭连接
                    return;
                }
                if(context->RecvStatu() != RECV_HTTP_OVER)
                {
                    return;
                }
                Route(req,&rsp);
                if(rsp._statu >=400)
                {
                    //出错了
                    ErrorHandler(req,&rsp);
                }
                //组织一个响应->发送给客户端
                WriteResponse(conn,req,rsp);
                //重置上下文
                context->ReSet();
                //短连接,直接关闭
                if(rsp.Close()) conn->Shutdown();
            }
        }

    private:
        Handlers _get_route;//get请求路由映射表
        Handlers _post_route;//post请求路由映射表
        Handlers _put_route;//put请求路由映射表
        Handlers _delete_route;//delete请求路由映射表
        std::string _basedir;//相对根路径->静态资源相对根目录
        Muduo::TcpServer _server;//Tcp服务器
    };
}